/***************************************************************************
 *            fosfor_button.c
 *
 *  Thu Oct 15 16:06:12 2009
 *  Copyright  2009  Kevin DeKorte
 *  <kdekorte@gmail.com>
 ****************************************************************************/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 */
 
#include "fosfor_button.h"
#include "support.h"

G_DEFINE_TYPE(FosforButton, fosfor_button, CLUTTER_TYPE_GROUP);
static GObjectClass *parent_class = NULL;

static void fosfor_button_dispose(GObject * object);
static void fosfor_button_paint(ClutterActor *actor);
static void fosfor_button_allocate(ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags);

static void fosfor_button_class_init(FosforButtonClass * class)
{
	// class init stuff
	parent_class = g_type_class_peek_parent(class);
	G_OBJECT_CLASS(class)->dispose = fosfor_button_dispose;
	CLUTTER_ACTOR_CLASS(class)->paint = fosfor_button_paint;
	CLUTTER_ACTOR_CLASS(class)->allocate = fosfor_button_allocate;

	g_signal_new("clicked", FOSFOR_TYPE_BUTTON, 
	    								G_SIGNAL_RUN_LAST, 
	    								G_STRUCT_OFFSET (FosforButtonClass, clicked), 
	    								NULL, NULL,
	    								gtk_marshal_VOID__VOID,G_TYPE_NONE,0);		
}

static gboolean on_rect_enter(ClutterActor * actor, ClutterEvent * event, gpointer data)
{
	FosforButton *button;

    button = FOSFOR_BUTTON(actor);
	if (button->sensitive && button->backlight)
		clutter_actor_animate(button->background, CLUTTER_LINEAR, 100, "opacity", 0xcc, NULL);

	return TRUE;
}

static gboolean on_rect_leave(ClutterActor * actor, ClutterEvent * event, gpointer data)
{
	FosforButton *button;

    button = FOSFOR_BUTTON(actor);
	if (button->sensitive && button->backlight)
		clutter_actor_animate(button->background, CLUTTER_LINEAR, 100, "opacity", 0x00, NULL);

	return TRUE;
}

static gboolean on_button_press(ClutterActor * actor, ClutterButtonEvent * event, gpointer data)
{
	FosforButton *button;
	gfloat x,y;
	
    button = FOSFOR_BUTTON(actor);
	if (button->sensitive && event->button == 1) {
		x = button->width / 2.0;
		y = button->height / 2.0;
		clutter_actor_animate(button->foreground, CLUTTER_LINEAR, 100, "x", x + 1.0, "y", y + 1.0, NULL);
		button->mouse_down = TRUE;
	}
	return TRUE;
}

static gboolean on_button_release(ClutterActor * actor, ClutterButtonEvent * event, gpointer data)
{
	FosforButton *button;
	gfloat x,y;
	
    button = FOSFOR_BUTTON(actor);
	if (button->sensitive && event->button == 1) {
		x = button->width / 2.0;
		y = button->height / 2.0;
		clutter_actor_animate(button->foreground, CLUTTER_LINEAR, 100, "x", x, "y", y, NULL);
		button->mouse_down = FALSE;
		g_signal_emit_by_name(button, "clicked");		
	}

	return TRUE;
}

static void fosfor_button_init(FosforButton * button)
{
	clutter_actor_set_reactive(CLUTTER_ACTOR(button), TRUE);
	g_signal_connect(CLUTTER_ACTOR(button), "enter-event", G_CALLBACK(on_rect_enter), NULL);
    g_signal_connect(CLUTTER_ACTOR(button), "leave-event", G_CALLBACK(on_rect_leave), NULL);
	g_signal_connect(CLUTTER_ACTOR(button), "button-press-event", G_CALLBACK(on_button_press), NULL);
    g_signal_connect(CLUTTER_ACTOR(button), "button-release-event", G_CALLBACK(on_button_release), NULL);
	
}

static void fosfor_button_create(FosforButton *button)
{
	ClutterContainer *group = CLUTTER_CONTAINER(button);
	cairo_t *cr;

	if (button->icon_name != NULL) {
		button->foreground = gtk_clutter_texture_new_from_icon_name(NULL,button->icon_name,button->size);
	} else if (button->stock_id != NULL) {
		button->foreground = gtk_clutter_texture_new_from_stock(clutter,button->stock_id,button->size);
	} else {
		return;
	}
	
	if (button->width == -1 && button->height == -1) {
		button->width = clutter_actor_get_width(button->foreground) * 1.5;
		button->height = clutter_actor_get_height(button->foreground) * 2.0;
		clutter_actor_set_size(CLUTTER_ACTOR(button), button->width, button->height);
	}
	
	clutter_actor_set_anchor_point(button->foreground, clutter_actor_get_width(button->foreground) / 2.0 ,clutter_actor_get_height(button->foreground) / 2.0);
	button->background = clutter_cairo_texture_new(clutter_actor_get_width(CLUTTER_ACTOR(button)) ,clutter_actor_get_height(CLUTTER_ACTOR(button)));
	clutter_actor_set_opacity(button->background, 0x00);

	clutter_container_add_actor(CLUTTER_CONTAINER(group), button->foreground);
	clutter_container_add_actor(CLUTTER_CONTAINER(group), button->background);
	clutter_actor_set_position(button->foreground, clutter_actor_get_width(CLUTTER_ACTOR(button)) / 2.0 ,clutter_actor_get_height(CLUTTER_ACTOR(button)) / 2.0);	
	clutter_actor_set_position(button->background, 0.0,0.0);	
	clutter_container_lower_child(CLUTTER_CONTAINER(group),button->background, NULL);
	clutter_actor_show_all(CLUTTER_ACTOR(button));

	clutter_cairo_texture_clear(CLUTTER_CAIRO_TEXTURE(button->background));

	cr = clutter_cairo_texture_create(CLUTTER_CAIRO_TEXTURE(button->background));

  	/* draw on the context */
	cairo_set_source_rgb(cr, 1.0,1.0,1.0);
	cairo_set_line_width(cr, 2.0);
	cairo_rounded_rectangle(cr, 0.0,0.0, clutter_actor_get_width(CLUTTER_ACTOR(button)) ,clutter_actor_get_height(CLUTTER_ACTOR(button)), 10.0);

	cairo_fill_preserve(cr);

	cairo_stroke(cr);	
	cairo_destroy (cr);

}



static void fosfor_button_dispose(GObject * object)
{
	FosforButton *button = FOSFOR_BUTTON(object);

	g_free(button->icon_name);
	g_free(button->stock_id);
	
	G_OBJECT_CLASS(parent_class)->dispose(object);
}

static void fosfor_button_paint(ClutterActor *actor)
{
	FosforButton *button = FOSFOR_BUTTON(actor);
	cairo_t *cr;

	if (!button->mouse_down)
		clutter_actor_set_position(button->foreground, button->width / 2.0 ,button->height / 2.0);	
	
	clutter_cairo_texture_set_surface_size(CLUTTER_CAIRO_TEXTURE(button->background), button->width, button->height);
	clutter_cairo_texture_clear(CLUTTER_CAIRO_TEXTURE(button->background));

	cr = clutter_cairo_texture_create(CLUTTER_CAIRO_TEXTURE(button->background));

  	/* draw on the context */
	//cairo_set_source_rgb(cr, 0.0,0.0,0.0);
	cairo_set_source_rgb(cr, window->style->base[1].red / 65535.0, window->style->base[1].green / 65535.0, window->style->base[1].blue / 65535.0);	
	cairo_set_line_width(cr, 2.0);
	cairo_rounded_rectangle(cr, 0.0,0.0, button->width ,button->height, 10.0);

	cairo_fill_preserve(cr);

	cairo_stroke(cr);	
	cairo_destroy (cr);

	CLUTTER_ACTOR_CLASS (parent_class)->paint(actor);
}

static void fosfor_button_allocate(ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags)
{

	FosforButton *button = FOSFOR_BUTTON(actor);

	button->width = box->x2-box->x1;
	button->height = box->y2-box->y1;

	if (button->foreground == NULL)
		fosfor_button_create(button);

	CLUTTER_ACTOR_CLASS(parent_class)->allocate(actor,box,flags);
	
}

ClutterActor *fosfor_button_new()
{
	FosforButton *button;

	button = g_object_new (FOSFOR_TYPE_BUTTON, NULL);
	button->icon_name = NULL;
	button->stock_id = NULL;
	button->sensitive = TRUE;
	button->backlight = TRUE;
	button->width = -1;
	button->height = -1;
	fosfor_button_create(button);

	return CLUTTER_ACTOR(button);
}

ClutterActor *fosfor_button_new_from_icon_name(const gchar *icon_name, GtkIconSize size)
{
	FosforButton *button;
	
	button = g_object_new (FOSFOR_TYPE_BUTTON, NULL);
	button->icon_name = g_strdup(icon_name);
	button->stock_id = NULL;
	button->size = size;
	button->sensitive = TRUE;
	button->backlight = TRUE;
	button->width = -1;
	button->height = -1;
	
	fosfor_button_create(button);

	return CLUTTER_ACTOR(button);

}

ClutterActor *fosfor_button_new_from_stock(const gchar *stock_id, GtkIconSize size)
{
	FosforButton *button;
	
	button = g_object_new (FOSFOR_TYPE_BUTTON, NULL);
	button->icon_name = NULL;
	button->stock_id = g_strdup(stock_id);
	button->size = size;
	button->sensitive = TRUE;
	button->backlight = TRUE;
	button->width = -1;
	button->height = -1;
	fosfor_button_create(button);


	return CLUTTER_ACTOR(button);

}

void fosfor_button_set_from_icon_name(FosforButton *button, const gchar *icon_name, GtkIconSize size)
{
	
	if (button->icon_name)
		g_free(button->icon_name);
	button->icon_name = g_strdup(icon_name);
	button->size = size;
	if (button->foreground == NULL) {
		fosfor_button_create(button);
	} else {
		gtk_clutter_texture_set_from_icon_name(CLUTTER_TEXTURE(button->foreground),clutter,button->icon_name,button->size,NULL);
	}

}

void fosfor_button_set_from_stock(FosforButton *button, const gchar *stock_id, GtkIconSize size)
{

	if (button->stock_id)
		g_free(button->stock_id);
	button->stock_id = g_strdup(stock_id);
	button->size = size;
	if (button->foreground == NULL) {
		fosfor_button_create(button);
	} else {
		gtk_clutter_texture_set_from_stock(CLUTTER_TEXTURE(button->foreground),clutter,button->stock_id,button->size,NULL);
	}

}

void fosfor_button_set_sensitive(FosforButton *button, gboolean sensitive)
{
	button->sensitive = sensitive;
	if (sensitive)
		clutter_actor_set_opacity(button->foreground, 255);
	else 
		clutter_actor_set_opacity(button->foreground, 128);
		
}

gboolean fosfor_button_get_sensitive(FosforButton *button)
{
	return button->sensitive;
}

void fosfor_button_set_backlight(FosforButton *button, gboolean backlight)
{
	button->backlight = backlight;
}

gboolean fosfor_button_get_backlight(FosforButton *button)
{
	return button->backlight;
}

